package action

import (
	"fmt"
	"strings"

	"gitee.com/sansaniot/ssiot-core/logger"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	cDto "ssdevice/common/dto"
	"ssdevice/common/middleware/mqtt"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/query"
)

type Config struct {
	Orm *gorm.DB
}

func (action *Config) Execute(topic string, jsonData map[string]interface{}) {
	devSn := strings.Split(topic, "/")[3]
	_, to := AutoLogin(action.Orm, devSn, jsonData)
	code := 200
	msg := "success"
	if strings.Contains(topic, "/config/get") {
		reqPath := utils.GetFieldFromJson([]string{"data", "path"}, jsonData)
		path := utils.If(reqPath != nil, reqPath, "").(string)
		// 获取profile.config
		needSub := strings.HasSuffix(topic, "/subdevice")
		err, profilePathResult := getDevConfig(action.Orm, devSn, path, needSub)
		if err != nil {
			logger.Error(err)
			code = 500
			msg = err.Error()
		}
		// 响应
		ackTopic := fmt.Sprintf("/iot/%s/%s/config/get/ack", devSn, constant.TopicPlaceholder)
		ackData := map[string]interface{}{
			"sid":  jsonData["sid"],
			"to":   to,
			"from": constant.TopicPlaceholder,
			"code": code,
			"msg":  msg,
			"data": profilePathResult,
		}
		mqtt.MqttClient.Publish(ackTopic, utils.MapToBytes(ackData))
	} else if strings.Contains(topic, "/config/set") {
		dataObj := jsonData["data"]
		if dataObj == nil {
			return
		}
		dataStr := string(utils.MapToBytes(dataObj.(map[string]interface{})))
		sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '{config}', jsonb_update(data #> '{config}', '" + dataStr + "' :: jsonb ) ) where dev_sn = '%s'"
		// 防止字符串中存在?占位符
		sql = fmt.Sprintf(sql, devSn)
		if err := action.Orm.Raw(sql).Scan(&models.SysDevConfig{}).Error; err != nil {
			code = 500
			msg = err.Error()
		}
		// 响应
		ackTopic := fmt.Sprintf("/iot/%s/%s/config/set/ack", devSn, constant.TopicPlaceholder)
		ackData := map[string]interface{}{
			"sid":  jsonData["sid"],
			"to":   to,
			"from": constant.TopicPlaceholder,
			"code": code,
			"msg":  msg,
		}
		mqtt.MqttClient.Publish(ackTopic, utils.MapToBytes(ackData))
	}
}

func getDevConfig(db *gorm.DB, sn, path string, needSub bool) (err error, result map[string]interface{}) {
	devConfig := &models.SysDevConfig{}
	devConfig.Model.Orm = db
	// 查询config
	if err = devConfig.FindOne(devConfig, cDto.MakeCondition(query.SysDevConfigQuery{Sn: sn})); err != nil {
		return
	}
	obj := utils.BytesToMap(devConfig.Data)["config"]
	if obj == nil {
		return
	}
	config := obj.(map[string]interface{})
	if needSub {
		// 网关自己的不要
		config = map[string]interface{}{}
		// 组装子设备config
		var subdeviceJson map[string]interface{}
		if subdeviceJson, err = devConfig.GetSubDeviceConfig(sn); err != nil {
			return
		}
		for k, v := range subdeviceJson {
			config[k] = v
		}
	}
	if len(path) > 0 {
		paths := strings.Split(path, ".")
		child := utils.GetFieldFromJson(paths, config)
		tmp := map[string]interface{}{}
		t(tmp, paths, 0, child)
		result = tmp
	} else {
		result = config
	}
	return
}

// 递归结果格式，适配终端协议定义
func t(m map[string]interface{}, paths []string, n int, final interface{}) {
	if n == len(paths)-1 {
		m[paths[n]] = final
		return
	}
	m[paths[n]] = map[string]interface{}{}
	t(m[paths[n]].(map[string]interface{}), paths, n+1, final)
}
